#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// REVIEW: am sters coment'ul ala, era prea evident
int adunarea(char* nume);
int scaderea(char* nume);
int inmultirea(char* nume);
int impartirea(char* nume);
void afiseaza_meniu(char* nume);
void citeste_optiune(int& optiune);
void interpreteaza_optiune(char* nume, int optiune);

/* REVIEW:
 Niste chestii generale:
 - Scrie ori in romana, ori in engleza (altfel arata urat): suma, nume, raspuns
 - Initializeaza'ti variabilele cand le declari. Daca nu o faci la declaratie intr'o zi s'ar putea sa uiti sa initializezi o variabila, si o sa'ti para rau
 - Daca intelegi ce face codul ce l'ai scris atunci demonstreaza asta punand comentarii. O sa te ajute si pe tine sa'l intelegi peste o saptamana (cand nu mai esti la fel de familiar cu codul), si va ajuta si pe altii care iti citesc codul
 - Incearca sa scrii doar o instructiune pe linie, altfel nu va fi la fel de usor de citit codul, si vei intampina probleme la debugging
*/
int main()
{
	char nume[40] = ""; // REVIEW: Nu ai avut nevoie de pointer "char* nume[40]"
	int optiune = 0; // REVIEW: "nm" nu era un nume prea sugestiv. Am redenumit'o in "optiune"

	{
		// REVIEW: Fii consecvent, foloseste ori puts, ori printf. Cand o sa trebuiasca sa cauti toate locurile de unde printezi, o sa'ti fie mai usor daca ai folosit acceasi functie si nu trebuie sa cauti dupa mai multe keyword'uri
		// REVIEW: Recomand sa folosesti doar printf si scanf, dar e la alegerea ta

		// Citim numele player'ului
		puts("Sa incepem cu ceva simplu... \nCum te numesti?");
		fgets(nume, sizeof(nume), stdin); // REVIEW: gets e vulnerabil la buffer overflows. Foloseste fgets si specifica si lungimea maxima
		// Mesaj de intampinare
		printf("Salut, %s!\n",  nume);
		// Asteptam pana apasa o tasta
		getchar();
		// Curatam ecranul
		system("clear");
	}

	// Din joc se iese doar selectand optiunea Iesire
	while(1)
	{
		// REVIEW: Cand pui un comment care'ti zice ca in locul ala lipseste niste cod pune TODO, asa o sa'ti fie mai usor sa gasesti toate locurile unde mai ai de lucru
		// TODO: de adaugat delay

		// REVIEW: Am identificat codul de'aici ca fiind: afisarea unui meniu, citirea unei optiuni selectate si interpretarea optiunii. Am extras codul in cateva proceduri pe care le'am apelat. Daca ai mai mult cod care face niste chestie bine definita extrage'l intr'o procedura (sau mai multe) si apeleaz'o. Iti va face codul mai usor de citit. Nu'i mare bai daca nu faci de la inceput, dar incearca cand poti

		afiseaza_meniu(nume);
		citeste_optiune(optiune);
		interpreteaza_optiune(nume, optiune);
	}
	// REVIEW: Chiar daca stii sigur ca nu se va ajunge pana la linia asta, trebuie neaparat sa returnezi o valoare ca default, din moment ce ai "int main()". Unele compilatoare iti vor da warning.
	return -1;
}

// REVIEW: Am facut review doar la functia asta, celelalte 3 sunt copii fidele (mai putin operatia). Cel mai bine ar fi daca ai putea face o singura functie, si sa se cheme cu diferite operatii. Asta ai putea reusi cu un macro
int adunarea(char* nume)
{
	// REVIEW: Da nume mai sugestive
	int exercitiu = 0, nivel = 0, puncte = 0, raspuns = 0, suma_puncte = 0;
	int rand1 = 0, rand2 = 0;

	// Exista 4 nivele
	for(nivel = 1; nivel <= 4; nivel++)
	{
		puts("Jocul incepe! 'Enter' cand esti pregatit!");
		getchar();

		// REVIEW: Pune un comentariu care descrie cate exercitii sunt per nivel
		for(exercitiu = 2; exercitiu < (8 * nivel); exercitiu++)
		{
			// Curata ecranul
			system("clear");

			// Afiseaza informatii: numarul nivelului si al exercitiului
			printf("Nivel %i \n\n", nivel);
			printf("Exercitiul  %i\n", exercitiu - 1);

			// Genereaza doua numere aleatoare
			rand1 = rand() % (nivel * 19 + 100);
			rand2 = rand() % (exercitiu * 21 + 100);

			// Afiseaza exercitiul
			printf("%i+\n%i=", rand1, rand2);
			// Citeste raspunsul
			scanf("%i", &raspuns);

			// Genereaza numarul de puncte care sunt in joc
			puncte = (rand() % 20) + 2;

			// Verifica raspunsul jucatorului
			if (raspuns == (rand1 + rand2))
			{
				// Raspuns corect - adunam punctele
				printf("Bravo %s, ai cistigat %i puncte\n", nume, puncte);
				suma_puncte = suma_puncte + puncte;
			}
			else
			{
				// Raspuns gresit - scadem punctele
				printf("Imi pare rau, %s....ai pierdut %i puncte\n", nume, puncte);
				suma_puncte = suma_puncte - puncte;
			}
			// REVIEW: Daca in ambele cazuri chemi getchar, atunci pune instructiunile in afara if/else
			getchar();getchar();
		}
		// Afiseaza statistica de final de joc
		printf("\t\2\3\4Felicitari %s, la nivelul %i ai acumulat  %i puncte", nume, nivel, suma_puncte);
		getchar();
	}
	getchar();
	return suma_puncte;
}


int scaderea(char* nume)
{ int exercitiu, nivel, puncte, raspuns, suma;
	int rand1, rand2;
	suma=0;
	for(nivel=1; nivel<5; nivel++)
	{
		puts("Jocul incepe! 'Enter' cand esti pregatit!");
		getchar();
		system("clear");
		for(exercitiu=2; exercitiu<(8*nivel); exercitiu++)
		{
			system("clear");
			printf("Nivel %i \n\n", nivel);
			printf("Exercitiul  %i\n", exercitiu-1);
			rand1=rand()%(nivel*19+100);
			rand2=rand()%(exercitiu*21+100);
			rand1=rand1+300;
			printf("%i-\n%i=", rand1, rand2);
			scanf("%i", &raspuns);
			puncte=(rand()%20)+2;

			if (raspuns==(rand1-rand2))
			{
				printf("Bravo %s, ai cistigat %i puncte\n", nume, puncte);
				suma=suma+puncte;
				getchar();getchar();
			}
			else
			{
				printf("Imi pare rau, %s....ai pierdut %i puncte\n", nume, puncte);
				suma=suma-puncte;
				getchar();getchar();
			}
		}
		printf("\t\2\3\4Felicitari %s, la nivelul %i ai acumulat  %i puncte", nume, nivel,  suma);
		getchar();
	}
	getchar();
	return suma;
}


int inmultirea(char* nume)
{ int exercitiu, nivel, puncte, raspuns, suma;
	int rand1, rand2;
	suma=0;
	for(nivel=1; nivel<5; nivel++)
	{
		puts("Jocul incepe! 'Enter' cand esti pregatit!");
		getchar();
		system("clear");
		for(exercitiu=2; exercitiu<(8*nivel); exercitiu++)
		{
			system("clear");
			printf("Nivel %i \n\n", nivel);
			printf("Exercitiul  %i\n", exercitiu-1);
			rand1=rand()%(nivel*19+100);
			rand2=rand()%(exercitiu*21+100);
			printf("%i*\n%i=", rand1, rand2);
			scanf("%i", &raspuns);
			puncte=(rand()%20)+2;

			if (raspuns==(rand1*rand2))
			{
				printf("Bravo %s, ai cistigat %i puncte\n", nume, puncte);
				suma=suma+puncte;
				getchar();getchar();
			}
			else
			{
				printf("Imi pare rau, %s....ai pierdut %i puncte\n",
						nume, puncte);
				suma=suma-puncte;
				getchar();getchar();
			}
		}
		printf("\t\2\3\4Felicitari %s, la nivelul %i ai acumulat  %i puncte", nume, nivel,  suma);
		getchar();
	}
	getchar();
	return suma;
}


int impartirea(char* nume)
{ int exercitiu, nivel, puncte, raspuns, suma;
	int rand1, rand2;
	suma=0;
	for(nivel=1; nivel<5; nivel++)
	{
		puts("Jocul incepe! 'Enter' cand esti pregatit!");
		getchar();
		system("clear");
		for(exercitiu=2; exercitiu<(8*nivel); exercitiu++)
		{
			system("clear");
			printf("Nivel %i \n\n", nivel);
			printf("Exercitiul  %i\n", exercitiu-1);
			rand1=rand()%(nivel*19+100);
			rand2=rand()%(exercitiu*21+100);
			rand1=rand1+242;
			printf("%i/\n%i=", rand1, rand2);
			scanf("%i", &raspuns);
			puncte=(rand()%20)+2;

			if (raspuns==(rand1/rand2))
			{
				printf("Bravo %s, ai cistigat %i puncte\n",
						nume, puncte);
				suma=suma+puncte;
				getchar();getchar();
			}
			else
			{
				printf("Imi pare rau, %s....ai pierdut %i puncte\n",
						nume, puncte);
				suma=suma-puncte;
				getchar();getchar();
			}
		}
		printf("\t\2\3\4Felicitari %s, la nivelul %i ai acumulat  %i puncte", nume, nivel,  suma);
		getchar();
	}
	getchar();
	return suma;
}

// Afiseaza optiunile posibile ale jocului
void afiseaza_meniu(char* nume) {
	int i = 0;
	// Curata ecranul
	system("clear");
	puts(" \t Jocul LOGIC");
	printf(" \2 \3 \4 \2 Salut, %s! \2 \4 \3 \2 \n", nume);
	for(i=0; i<40; i++)
	{printf("%c", 178);}
	puts(" ");
	for(i=0; i<40; i++)
	{printf("%c", 176);}
	puts(" ");
	puts(" Alege o optiune: \n\n");
	puts("  1. Adunari");
	puts("  2. Scaderi");
	puts("  3. Imultiri");
	puts("  4. Impartiri\n");
	puts("  5. Schimba nume jucator\n"); // REVIEW: "Nume jucator" nu era destul de clar, am schimbat in "Schimba nume jucator"
	puts("  6. Informatii\n\n");
	// puts("  7. Cumpara(ceva)"); // TODO: Optiunea asta nu exista. Poate vrei sa o implementezi pe viitor, sau ai sters'o. Rezolva TODO'ul asta stergand linia sau implementand optiunea Cumpara
	puts("  13. Iesire");;
	for(i=0; i<40; i++)
	{printf("%c", 177);}
	puts(" ");
	for(i=0; i<40; i++)
	{printf("%c", 177);}
	puts(" ");
}

// Citeste optiunea selectata din meniu
void citeste_optiune(int& optiune) {
	printf(" Introdu numarul optiunii:  >> ");
	scanf("%i", &optiune);
}

void interpreteaza_optiune(char* nume, int optiune) {
	int suma = 0;
	/* REVIEW: Am identificat ca fiecare joc poate fi impartit in 3 etape:
	 - initializare: inainte sa inceapa jocul se curata ecranul si se afiseaza numele jocului
	 - jocul propriu-zis: incepe jocul
	 - se afiseaza rezultatul obtinut in joc si se asteapta apasarea unei taste
	 Din moment ce s'au indentificat mai multe asemanari s'ar putea rescrie putin codul, Ai putea pune clear inainte de switch, getchar() dupa switch, inauntrul functiei adunarea() ai putea afisa "Jocul Adunari" si ".. s-a terminat" si numarul de puncte acumulate
	 */
	switch(optiune)
	{
		case 1: // Adunari
			{   
				system("clear");
				puts("Jocul Adunari");

				suma = adunarea(nume);

				puts("Jocul Adunari s-a terminat"); // REVIEW: "s-a" terminat :)
				printf("%s, in acest joc ai acumulat %i puncte", nume, suma);
				getchar(); break;
			}
		case 2: // Scaderi
			{    
				system("clear");
				puts("Jocul Scaderi");

				suma = scaderea(nume);
				puts("Jocul Scaderi s-a terminat");
				printf("%s, in acest joc ai acumulat %i puncte", nume, suma);
				getchar(); break;

			}
		case 3: // Inmultiri
			{   
				system("clear");
				puts("Jocul Imultiri");

				suma = inmultirea(nume);
				puts("Jocul Imultiri s-a terminat");
				printf("%s, in acest joc ai acumulat %i puncte", nume, suma);
				getchar(); break;
			}
		case 4: // Impartiri
			{   
				system("clear");
				puts("Jocul Impartiri");

				suma = impartirea(nume);
				puts("Jocul Impartiri sa terminat");
				printf("%s, in acest joc ai acumulat %i puncte", nume, suma);
				getchar(); break;
			}
		case 5: // Schimba nume jucator
			{
				system("clear");
				puts(" Introdu un alt nume:");
				fflush(stdin);
				getchar();
				fgets(nume, sizeof(nume), stdin); // REVIEW: gets is vulnerable. use fgets to specify also the maximum length
				printf("Salut, %s !",  nume);
				getchar();getchar(); break;
			}
		case 6: // Informatii
			{   
				system("clear");
				puts(" Informatii:");
				puts("Acesta este un mic joc, in care, ca sa invingi, trebuie sa rezolvi \nexercitiile propuse.");
				puts("Regula este urmatoarea: daca raspunzi corect, primesti puncte, daca \nnu,  pierzi puncte");
				puts("Poti utiliza un stilou si o foaie pentru rezolvare, la exercitiile mai\n complicate");
				getchar(); break;
			}
		case 13: // Iesire
			{
				int raspuns = 0; // REVIEW: Am mutat aici declaratia varibilei pentru ca scopul ei e doar blocul asta de cod, daca nu s'a selectat optiunea iesire nu are rost sa fie declarata
				puts("Chiar doresti sa iesi din joc? (1=Da/2=Nu)");
				puts("(Raspunde cu cifra optiunii)");
				scanf("%i", &raspuns);
				if (raspuns == 1) { puts(" La revedere!"); getchar(); exit(1);} // Iesire din program
				getchar(); break;
			}

		default: // Optiune inexistenta
			{
				puts("Nu exista asa optiune!");
				getchar(); break;
			}
	}
}
